package com.hzb.myvpn;

import android.content.Intent;
import android.content.SharedPreferences;
import android.net.VpnService;
import android.preference.PreferenceManager;
import android.util.Log;

import com.hzb.myvpn.model.AndroidTunDev;
import com.hzb.myvpn.model.BaseVpn;
import com.hzb.myvpn.model.BaseVpn.VpnConnectException;
import com.hzb.myvpn.model.MyVpn;
import com.hzb.myvpn.model.VpnConfig;
import com.hzb.myvpn.model.ITunDev.ITunDevFactory;

public class MyVpnService extends VpnService {
    private final class VpnThread extends Thread {
        
        
        private VpnThread(String threadName) {
            super(threadName);
        }

        @Override
        public void run() {
            for (int t=0; running; t+=1000) {
                long startTime = System.currentTimeMillis();
                try {
                    Log.i("Vpn", "Start running vpn");
                    synchronized (lock) {
                        vpn = new MyVpn(config, tunFactory, MyVpnService.this);
                    }
                    vpn.tunneling();
                } catch (VpnConnectException e) {
                    Log.e("Vpn", "", e);
                } catch (Exception e) {
                    Log.e("Vpn", "", e);
                } finally {
                    synchronized (lock) {
                        vpn = null;
                    }
                }
                try {
                    if (System.currentTimeMillis() - startTime > 30000) t = 0;
                    if (t > 0) {
                        Log.i("Vpn", "Retry connnect after " + t + "ms");
                        Thread.sleep(t);
                    }
                } catch (InterruptedException e) {
                    Log.i("Vpn", "Interrupted");
                    break;
                }
            }
            Log.i("Vpn", "VpnThread exit");
            synchronized (lock) {
                vpnThread = null;
                running = false;
            }
        }
    }

    private Object lock = new Object();
    private boolean running = false;
    private volatile BaseVpn vpn;
    private volatile Thread vpnThread;
    private ITunDevFactory tunFactory;
    private VpnConfig config;
    
    private SharedPreferences prefs;
    
    private int getPrefInt(String key, int defaultValue) {
        String valStr = prefs.getString(key, "");
        if (!valStr.isEmpty()) {
            try {
                return Integer.parseInt(valStr);
            } catch (Exception e) {}
        }
        return defaultValue;
    }
    
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        synchronized (lock) {
            if (running) {
                stopVpn();
                return START_NOT_STICKY;
            }
            config = new VpnConfig();
            tunFactory = new AndroidTunDev.Factory(this);
            try {
                prefs = PreferenceManager.getDefaultSharedPreferences(this);
                config.setHost(prefs.getString("host", "oa.hzbn.tk"));
                config.setPort(getPrefInt("port", 15045));
                config.setUsername(prefs.getString("username", "test"));
                config.setPassword(prefs.getString("password", "test"));
                config.setHeartbeat(getPrefInt("clientHeartbeat", 300));
                config.setTimeout(getPrefInt("clientTimeout", 360));
                config.setServerHeartbeat(getPrefInt("serverHeartbeat", 300));
                config.setServerTimeout(getPrefInt("serverTimeout", 360));

                vpnThread = new VpnThread("VpnThread");
                vpnThread.start();
                running = true;
            } catch (Exception e) {
                Log.e("Vpn", "Start vpn error", e);
                stopSelf();
            } finally {
                prefs = null;
            }
        }
        return START_STICKY;
    }
    
    private void stopVpn() {
        running = false;
        if (vpn != null) vpn.close();
        if (vpnThread != null) vpnThread.interrupt();
        vpn = null;
        vpnThread = null;
        stopSelf();
    }

    @Override
    public void onRevoke() {
        super.onRevoke();
        synchronized (lock) {
            stopVpn();
        }
    }
}
